#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Token {
  /// An atomic token (a digit or a letter).
  Atom(char),
  /// An operator token (like '+', '-', '*', '/', etc.).
  Op(char),
  Eof,
}

pub struct Lexer {
  tokens: Vec<Token>,
}

impl Lexer {
  pub fn new(input: &str) -> Lexer {
    let mut tokens = input
      .chars()
      .filter(|it| !it.is_ascii_whitespace())
      .map(|c| match c {
        // Letters and digits are atoms.
        '0'..='9' | 'a'..='z' | 'A'..='Z' => Token::Atom(c),
        // All other characters are considered operators.
        _ => Token::Op(c),
      })
      .collect::<Vec<_>>();
    tokens.reverse();
    Lexer { tokens }
  }

  /// Consumes and returns the next token from the lexer.
  pub fn next(&mut self) -> Token {
    self.tokens.pop().unwrap_or(Token::Eof)
  }

  /// Peeks at the next token without consuming it.
  pub fn peek(&mut self) -> Token {
    self.tokens.last().copied().unwrap_or(Token::Eof)
  }

  pub fn tokenize(&self) -> Vec<Token> {
    self.tokens.clone()
  }
}
